/*
Rc 与 Arc
Rust 所有权机制要求一个值只能有一个所有者，在大多数情况下，都没有问题，但是考虑以下情况：

在图数据结构中，多个边可能会拥有同一个节点，该节点直到没有边指向它时，才应该被释放清理
在多线程中，多个线程可能会持有同一个数据，但是你受限于 Rust 的安全机制，无法同时获取该数据的可变引用

通过引用计数的方式，允许一个数据资源在同一时刻拥有多个所有者。
这种实现机制就是 Rc 和 Arc，前者适用于单线程，后者适用于多线程
*/

// 希望在堆上分配一个对象供程序的多个部分使用且无法确定哪个部分最后一个结束时，就可以使用 Rc 成为数据值的所有者
#[cfg(test)]
mod rc {
    use std::rc::Rc;

    #[test]
    fn count() {
        let ss = String::from("hello, world");
        // s在这里被转移给a
        let bo = Box::new(ss);
        println!("{}", bo);
        // 报错！此处继续尝试将 s 转移给 b
        // let b = Box::new(s);

        let ss = Rc::new(String::from("hello, world"));
        println!("{} {}", ss, Rc::strong_count(&ss)); //智能指针 Rc<T> 在创建时，还会将引用计数加 1

        // Rc::clone 克隆了一份智能指针 Rc<String>，并将该智能指针的引用计数增加到 2。
        // clone 仅仅复制了智能指针并增加了引用计数，并没有克隆底层数据，只是共享了底层的字符串 ss，这种复制效率是非常高的

        let rr = Rc::clone(&ss); //由于 aa 和 rr 是同一个智能指针的两个副本，因此通过它们两个获取引用计数的结果都是 2。

        println!("{} {}", ss, Rc::strong_count(&ss)); //2
        println!("{} {}", rr, Rc::strong_count(&rr)); //22
    }

    #[test]
    fn count_a() {
        let a = Rc::new(String::from("test ref counting"));
        println!("count after creating a = {}", Rc::strong_count(&a)); //初始化 1
        let b = Rc::clone(&a); // 复制了一份引用
        println!("count after creating b = {}", Rc::strong_count(&a)); // 2
        {
            let c = Rc::clone(&a);
            println!("count after creating c = {}", Rc::strong_count(&c)); //3
            //回收  Rc<T> 实现了 Drop
        }

        println!("count after c goes out of scope = {}", Rc::strong_count(&a)); //2
    }
    //     Rc<T> 是指向底层数据的不可变的引用，因此你无法通过它来修改数据
    //     Rust 的借用规则：要么存在多个不可变借用，要么只能存在一个可变借用。
}

/*
Rc 简单总结
Rc/Arc 是不可变引用，你无法修改它指向的值，只能进行读取，如果要修改，需要配合后面章节的内部可变性 RefCell 或互斥锁 Mutex
    一旦最后一个拥有者消失，则资源会自动被回收，这个生命周期是在编译期就确定下来的
    Rc 只能用于同一线程内部，想要用于线程之间的对象共享，你需要使用 Arc
    Rc<T> 是一个智能指针，实现了 Deref 特征，因此你无需先解开 Rc 指针，再使用里面的 T，而是可以直接使用 T，例如上例中的 gadget1.owner.name
*/

#[cfg(test)]
mod rc_example {
    use std::rc::Rc;

    struct Owner {
        name: String,
        // ...其它字段
    }

    struct Gadget {
        id: i32,
        owner: Rc<Owner>,
        // ...其它字段
    }

    #[test]
    fn struct_rc() {
        // 创建一个基于引用计数的 `Owner`.
        let gadget_owner: Rc<Owner> = Rc::new(Owner {
            name: "Gadget Man".to_string(),
        });
        println!("gadget_owner {}", Rc::strong_count(&gadget_owner)); //1

        // 创建两个不同的工具，它们属于同一个主人
        let gadget1 = Gadget {
            id: 1,
            owner: Rc::clone(&gadget_owner),
        };
        let gadget2 = Gadget {
            id: 2,
            owner: Rc::clone(&gadget_owner),
        };
        println!("gadget_owner {}", Rc::strong_count(&gadget_owner)); //3

        // 释放掉第一个 `Rc<Owner>`
        drop(gadget_owner); //drop 掉其中一个智能指针引用，而不是 drop 掉 owner 数据
        // println!("gadget_owner {}", Rc::strong_count(&gadget_owner)); //err
        println!("gadget_owner owner {}", Rc::strong_count(&gadget2.owner)); //2

        // 尽管在上面我们释放了 gadget_owner，但是依然可以在这里使用 owner 的信息
        // 原因是在 drop 之前，存在三个指向 Gadget Man 的智能指针引用，上面仅仅
        // drop 掉其中一个智能指针引用，而不是 drop 掉 owner 数据，外面还有两个
        // 引用指向底层的 owner 数据，引用计数尚未清零
        // 因此 owner 数据依然可以被使用
        println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name);
        println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name);

        // 在函数最后，`gadget1` 和 `gadget2` 也被释放，最终引用计数归零，随后底层
        // 数据也被清理释放
    }

    #[test]
    fn main() {
        let s = Rc::new(String::from("多线程漫游者"));

        for _ in 0..10 {
            let s = Rc::clone(&s);
            // 通过 thread::spawn 创建一个线程，然后使用 move 关键字把克隆出的 s 的所有权转移到线程中

            // 表面原因是 Rc<T> 不能在线程间安全的传递，实际上是因为它没有实现 Send 特征，而该特征是恰恰是多线程间传递数据的关键
            // 由于 Rc<T> 需要管理引用计数，但是该计数器并没有使用任何并发原语，因此无法实现原子化的计数操作，最终会导致计数错误

            //err
            // let handle = thread::spawn(move || {
            //     println!("{}", s)
            // });
        }
    }
}

// Arc 是 Atomic Rc 的缩写，顾名思义：原子化的 Rc<T> 智能指针
// 原因在于原子化或者其它锁虽然可以带来的线程安全，但是都会伴随着性能损耗，而且这种性能损耗还不小
#[cfg(test)]
mod arc_example {
    use std::sync::Arc;
    use std::thread;

    #[test]
    fn struct_rc() {
        let s = Arc::new(String::from("多线程漫游者"));
        for _ in 0..10 {
            let s = Arc::clone(&s);
            let handle = thread::spawn(move || println!("{} :{}", s, Arc::strong_count(&s)));
        }
    }
}
/*
Rc 和 Arc 的区别在于，后者是原子化实现的引用计数，因此是线程安全的，可以用于多线程中共享数据。
这两者都是只读的，如果想要实现内部数据可修改，必须配合内部可变性 RefCell 或者互斥锁 Mutex 来一起使用。

*/
